#include "instructions/stores/xastore.h"
#include "rtda/heap/object.h"
#include "instructions/base/utils.hpp"

namespace jvm {
    namespace instructions {

        void AASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            auto ref = stack->popRef();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& refs = arrRef->refs();
            utils::checkIndex(refs.size(), index);
            refs[index] = ref;
        }

        void BASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            int32_t val = stack->popInt();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& bytes = arrRef->bytes();
            utils::checkIndex(bytes.size(), index);
            bytes[index] = static_cast<int8_t>(val);
        }

        void CASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            int32_t val = stack->popInt();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& chars = arrRef->chars();
            utils::checkIndex(chars.size(), index);
            chars[index] = static_cast<uint16_t>(val);
        }

        void DASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            double val = stack->popDouble();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& doubles = arrRef->doubles();
            utils::checkIndex(doubles.size(), index);
            doubles[index] = static_cast<double>(val);
        }

        void FASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            float val = stack->popFloat();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& floats = arrRef->floats();
            utils::checkIndex(floats.size(), index);
            floats[index] = static_cast<float>(val);
        }

        void IASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            int32_t val = stack->popInt();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& ints = arrRef->ints();
            utils::checkIndex(ints.size(), index);
            ints[index] = val;
        }

        void LASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            int64_t val = stack->popLong();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& longs = arrRef->longs();
            utils::checkIndex(longs.size(), index);
            longs[index] = val;
        }

        void SASTORE::execute(std::shared_ptr<rtda::Frame> pframe) {
            auto&& stack = pframe->getOperandStack();
            int32_t val = stack->popInt();
            int32_t index = stack->popInt();
            auto arrRef = stack->popRef();

            utils::checkNotNil(arrRef);
            auto&& shorts = arrRef->shorts();
            utils::checkIndex(shorts.size(), index);
            shorts[index] = static_cast<int16_t>(val);
        }

    } // namespace instructions
}// namespace jvm